package cn.iocoder.yudao.module.ad.plan.service;

import cn.iocoder.yudao.framework.business.audit.enums.AuditStatusEnum;
import cn.iocoder.yudao.framework.business.audit.pojo.form.AuditSaveDTO;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreQueryWrapper;
import cn.iocoder.yudao.framework.business.basic.pojo.vo.UserSimpleVO;
import cn.iocoder.yudao.framework.business.basic.service.CrudService;
import cn.iocoder.yudao.framework.business.basic.service.impl.MemberScopeService;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ad.plan.dal.dataobject.AdPlanDO;
import cn.iocoder.yudao.module.ad.plan.dal.mysql.AdPlanMapper;
import cn.iocoder.yudao.module.ad.plan.vo.AdPlanQueryDTO;
import cn.iocoder.yudao.module.ad.plan.vo.AdPlanSaveDTO;
import cn.iocoder.yudao.module.ad.plan.vo.AdminAdPlanVO;
import cn.iocoder.yudao.module.api.ad.plan.enums.AdPlanBillingTypeEnum;
import cn.iocoder.yudao.module.api.ad.plan.enums.AdPlanExceptTypeEnum;
import cn.iocoder.yudao.module.api.ad.plan.enums.AdPlanStatusEnum;
import cn.iocoder.yudao.module.api.infrastructure.config.ConfigApiV2;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.AdConfigRespDTO;
import cn.iocoder.yudao.module.api.member.user.MemberUserApi;
import cn.iocoder.yudao.module.api.shop.info.ShopInfoApi;
import cn.iocoder.yudao.module.api.shop.info.dto.ShopInfoDTO;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.Collection;
import java.util.Map;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.constant.ErrorCodeConstants.AUDIT_STATUS_DENIED_FOR_PASS;
import static cn.iocoder.yudao.framework.constant.ErrorCodeConstants.AUDIT_STATUS_DENIED_FOR_WAIT;
import static cn.iocoder.yudao.module.api.infrastructure.ConfigConstants.CONFIG_AD;

/**
 * 广告投放计划 Service 实现类
 *
 * @author 山野羡民（1032694760@qq.com）
 */
@Service
@Validated
public class AdminAdPlanServiceImpl extends MemberScopeService<AdPlanDO, AdminAdPlanVO, AdPlanQueryDTO> implements AdminAdPlanService, CrudService<AdPlanDO, AdminAdPlanVO, AdPlanSaveDTO, AdPlanQueryDTO> {

    @Resource
    private AdPlanMapper adPlanMapper;

    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private ShopInfoApi shopInfoApi;
    @Resource
    private ConfigApiV2 configApiV2;

    @Override
    public AdPlanMapper getInjectedMapper() {
        return adPlanMapper;
    }

    @Override
    public AdPlanDO convertToEntity(AdPlanSaveDTO param) {
        return BeanUtils.toBean(param, AdPlanDO.class);
    }

    @Nonnull
    @Override
    protected CoreQueryWrapper<AdPlanDO> buildQueryWrapper(AdPlanQueryDTO param) {
        CoreQueryWrapper<AdPlanDO> wrapper = super.buildQueryWrapper(param);
        wrapper.eqIfPresent("status", param.getStatus());
        wrapper.orderByDesc("id");
        return wrapper;
    }

    @Nonnull
    @Override
    protected Map<Long, UserSimpleVO> getUserSimpleMap(Collection<Long> userIds) {
        return memberUserApi.getUserSimpleMap(userIds);
    }

    @Override
    public void beforeCreate(AdPlanDO entity, @Nullable Long userId) {
        ShopInfoDTO shopInfo = shopInfoApi.getShopInfoByMemberUserId(userId);
        Assertions.notNull(shopInfo, "商户信息获取失败");
        entity.setAdvertiser(shopInfo.getName());
        entity.setUserId(shopInfo.getUserId());
        entity.setExceptType(AdPlanExceptTypeEnum.DURATION.getValue());
        AdConfigRespDTO config = configApiV2.getConfig(CONFIG_AD, AdConfigRespDTO.class);
        entity.setBillingType(AdPlanBillingTypeEnum.PLAY.getValue());
        entity.setBillingUnitPrice(config.getPlayUnitPrice());
        entity.setExceptExposureCount(entity.getBudgetPrice() / config.getExposureUnitPrice());
        entity.setExceptPlayCount(entity.getBudgetPrice() / config.getPlayUnitPrice());
        entity.setStatus(AdPlanStatusEnum.PAY.getValue());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAudit(AuditSaveDTO reqVO) {
        if (Objects.equals(reqVO.getAuditStatus(), AuditStatusEnum.WAIT.getValue())) {
            // 默认就是待审核状态，不允许从其他状态流转回来
            throw exception(AUDIT_STATUS_DENIED_FOR_WAIT);
        }
        // 校验存在
        AdPlanDO aDo = validateExists(reqVO.getId());
        if (!Objects.equals(aDo.getStatus(), AdPlanStatusEnum.AUDIT.getValue())) {
            // 审核通过的，已经创建相关信息，为保证数据完整性，不允许再修改审核状态
            throw exception(AUDIT_STATUS_DENIED_FOR_PASS);
        }
        if (Objects.equals(reqVO.getAuditStatus(), AuditStatusEnum.REJECT.getValue())) {
            aDo.setStatus(AdPlanStatusEnum.STOP.getValue());
        } else {
            aDo.setStatus(AdPlanStatusEnum.START.getValue());
        }
        aDo.setNote(reqVO.getAuditNote());
        getInjectedMapper().updateById(aDo);
    }

}
